package com.ctrip.corp.obt.shard.aop.shard;


import com.ctrip.corp.obt.generic.utils.Conditional;
import com.ctrip.corp.obt.shard.annotation.ShardModel;
import com.ctrip.corp.obt.shard.context.DataShardContext;
import com.ctrip.corp.obt.shard.exception.ShardException;
import com.ctrip.corp.obt.shard.handler.IShardingHandler;
import com.ctrip.corp.obt.shard.holder.ShardModelHolder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;

/**
 * @author marco.zheng
 * @version 1.0
 * @date 2022/02/09
 * @desc 根据 {@link ShardModel} 进行shard
 * @see
 * @since 1.0
 */
@Aspect
public class ShardModelDSAspect extends AbstractDataShardAspect {

    public ShardModelDSAspect(IShardingHandler shardingHandler) {
        super(shardingHandler);
    }

    @Pointcut("@annotation(com.ctrip.corp.obt.shard.annotation.ShardModel) || @within(com.ctrip.corp.obt.shard.annotation.ShardModel)")
    public void pointPackPath() {}

    @Around("pointPackPath()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        String pointPath = "";
        try {
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            pointPath = signature.toString();
            ShardModel shardModel = ShardModelHolder.get(method);
            String targetDataSource = shardModel.targetDataSource();
            Conditional.ofBlankAble(targetDataSource).ifNotEmpty(DataShardContext::setDBShardSource);
            // 只有当方法上添加了ShardModel，才能进行分表
            DataShardContext.allowTableReroute();
            preShard(shardModel.tableShardStrategy());
            // 执行目标方法
            return point.proceed();
        } catch (IllegalArgumentException | ShardException ex) {
            throw new ShardException(pointPath + " : " + ex.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            throw new ShardException("ShardModelDSAspect.doAround error path:" + pointPath);
        } finally {
            DataShardContext.clearDBShardSource();
        }
    }

}
